home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-02-18 | 43.2 KB | 1,573 lines |
- Newsgroups: comp.sources.unix
- From: brnstnd@nyu.edu (Dan Bernstein)
- Subject: v25i133: Generalized interface to pseudo-tty devices, Part07/09
- Sender: unix-sources-moderator@pa.dec.com
- Approved: vixie@pa.dec.com
-
- Submitted-By: brnstnd@nyu.edu (Dan Bernstein)
- Posting-Number: Volume 25, Issue 133
- Archive-Name: pty4/part07
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 7 (of 9)."
- # Contents: SESS.draft2 ptymain.c sigsched.c
- # Wrapped by vixie@cognition.pa.dec.com on Wed Feb 19 13:35:06 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'SESS.draft2' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'SESS.draft2'\"
- else
- echo shar: Extracting \"'SESS.draft2'\" \(11273 characters\)
- sed "s/^X//" >'SESS.draft2' <<'END_OF_FILE'
- An introduction to session management
- Daniel J. Bernstein
- draft 2
- X10/4/91
- X
- X
- X1. Session basics
- X
- X < session, n. ... 4. any period of activity. >
- X
- When a user sits down in front of a multi-user computer, gives his login
- name and password, and starts typing, he's begun a _session_. Within
- that session he might read mail, edit files, compile and run programs,
- and even play games. What happens if the screen explodes?
- X
- A typical UNIX system lets a user log in through a network, or over a
- phone connection between the user's modem and the computer's modem. But
- if the phone line suddenly becomes too noisy, or the network doesn't
- work, the user's connection may drop. The system will then terminate the
- login session. Any programs run by the user will be signalled that the
- connection was hung up. If they ask the user for input, they won't get
- any. If they produce output, the output will vanish.
- X
- Other operating systems are more helpful. VMS, for instance, keeps the
- session running inside the computer. When the user establishes another
- connection and logs in again, the computer asks if he'd like to
- reconnect to the original session. Programs started under the session
- won't notice what happened. This is a primitive form of _session
- management_. (It is also an abuse of terminology, as the ``session''---
- the ``period of activity''---really consists of two periods. On the
- other hand, from the point of view of the programs under the session,
- there hasn't been any interruption.)
- X
- This paper describes a session management system which the author has
- developed for BSD UNIX and its variants. In section 2 we describe the
- three fundamental operations making up the system. In section 3 we show
- how the system appears to novice users. In section 4 we give several
- examples of more complex session management techniques which cannot be
- performed under VMS.
- X
- X
- X2. sess, disconnect, reconnect
- X
- The session management system consists of three basic operations. To
- illustrate the operations we use pictures:
- X
- X user ==== tty ==== csh (1)
- X
- A double line, such as ====, represents a two-way flow of information.
- Here the user types characters, which the UNIX kernel processes inside a
- tty device and then sends to the user's shell, csh. What csh prints is
- then sent back through the tty to the user.
- X
- When csh starts a job, the picture changes:
- X
- X ---------------
- X / \
- X user ==== tty ==== csh who
- X \ |
- X \ sort
- X \ |
- X ------------ more
- X
- Here the user has started a pipeline, who | sort | more. To simplify the
- illustration somewhat we pretend that all I/O from the pipeline is sent
- through the shell:
- X
- X user ==== tty ==== csh ---- who
- X \ |
- X \ sort
- X \ |
- X -- more
- X
- A job consisting of only one process looks like this:
- X
- X user ==== tty ==== csh ==== vi
- X
- If the user's connection dies, the tty effectively disappears:
- X
- X csh ==== vi
- X
- Without a place to send input and output, csh and vi receive the HUP
- signal and die a messy death.
- X
- The first session management operation is sess. When the user, starting
- from picture (1), types ``sess ksh'', he creates a session:
- X
- X /------\ +------+
- X user ==== tty ==== csh ==== | conn | ==== | sess | === ksh
- X \------/ +------+
- X
- The session consists of the square box, called the _master_ because it's
- in charge of session management, with ksh running below it. The session
- is connected to the rounded box, also called the _signaller_ because it
- signals csh when the session is finished. Normally both boxes are
- completely transparent, and the user can start jobs under the session:
- X
- X /------\ +------+
- X user ==== tty ==== csh ==== | conn | ==== | sess | === ksh ==== vi (2)
- X \------/ +------+
- X
- X(In fact, from ksh's point of view, the sess box looks just like a tty.
- It is actually a _pseudo-tty_, also known as a _pseudo-terminal_.
- XFurther discussion of pseudo-terminals is beyond the scope of this
- paper.)
- X
- What happens if the user's connection drops? As before, the original tty
- disappears, and csh sputters and dies. The signaller disappears too:
- X
- X +------+
- X | sess | === ksh ==== vi
- X +------+
- X
- However, the session keeps running. sess doesn't mind being
- disconnected. It waits for a reconnect, as described below. Meanwhile,
- ksh doesn't have the slightest inkling that the connection is gone.
- X
- The user can in fact force a disconnect manually. This is the second
- fundamental operation. Starting from picture (2), if the user types
- X``disconnect'' to ksh, the connection will be severed:
- X
- X user ==== tty ==== csh
- X
- X +------+
- X | sess | === ksh ==== vi (3)
- X +------+
- X
- The signaller exits quietly, and the user can now type commands to csh.
- X
- How does the user reconnect to a disconnected session? He uses the third
- fundamental operation, the reconnect command. The system assigns each
- session a name. If the user starts a new session, it might look like
- this:
- X
- X /------\ +------+
- X user ==== tty ==== csh ==== | conn | ==== | sess | === qsh
- X \------/ +--p7--+
- X
- Here ``p7'' is this session's name. Say the disconnected session was
- named ``qb'':
- X
- X /------\ +------+
- X user ==== tty ==== csh ==== | conn | ==== | sess | === qsh
- X \------/ +--p7--+
- X
- X +------+
- X | sess | === ksh ==== vi
- X +--qb--+
- X
- If the user types ``reconnect qb'' to qsh, nothing happens immediately,
- but the signaller remembers his reconnect:
- X
- X /------\ +------+
- X user ==== tty ==== csh ==== | conn | ==== | sess | === qsh
- X \-+qb+-/ +--p7--+
- X
- X +------+
- X | sess | === ksh ==== vi
- X +--qb--+
- X
- As soon as session p7 exits (or is disconnected), the reconnect takes
- effect:
- X
- X /------\ +------+
- X user ==== tty ==== csh ==== | conn | ==== | sess | === ksh ==== vi
- X \------/ +--qb--+
- X
- Now it's just as if session qb had been connected all along. The user
- can type commands to vi. If the connection disappears again, he can
- reconnect again, any number of times.
- X
- Why doesn't reconnect take effect immediately? There are several
- reasons. Perhaps the most important is that before reconnecting the user
- may want to terminate the currently connected session---or he may want
- to disconnect it, so that he can reconnect to it later. This reconnect
- interface doesn't force one choice or the other. The user may also want
- to perform some lengthy operations before reconnecting, and it's easier
- to schedule the reconnect once and do it at his leisure than to have to
- worry about the reconnect after all the operations. Finally, it is very
- simple to simulate an immediate reconnect using the above operations, as
- detailed in section 4.
- X
- X
- X3. Session management for users
- X
- Most users will never have to learn anything about the sess, disconnect,
- or reconnect commands. If a connection dies, its owner will be shown a
- message like this when he logs in again:
- X
- X You have a disconnected session on /dev/ttyra, with these processes:
- X USER PID %CPU %MEM SZ RSS TT STAT START TIME COMMAND
- X shmoe 17790 0.0 0.9 176 504 ra T 12:47 0:01 vi paper.3
- X shmoe 17331 0.0 0.7 72 384 ra I 12:31 0:00 -bin/csh (csh)
- X shmoe 17330 0.0 0.5 104 264 ra S 12:31 0:00 pty -ds argv0 /bin/csh
- X Would you like to reconnect to that session?
- X If so, type its two-character extension, ra.
- X To instead start a new session as usual, just press return:
- X
- The user will recognize the ``paper.3'' he was editing, type ra, and be
- reconnected to his session. The program which handles this is called
- X``sessmenu''. While perhaps not as friendly as the reconnect facilities
- under some operating systems, sessmenu isolates even novices from the
- trauma of losing important work.
- X
- All sessions also keep track of a long name assigned by the user. The
- X``sessname'' command displays or sets the current session name:
- X
- X csh% sessname
- X session p7
- X csh% sessname 'writing net test program'
- X csh% sessname
- X session p7: writing net test program
- X csh%
- X
- The user can see all his sessions with ``sesslist'':
- X
- X csh% sesslist
- X session p7 pid 16614 slave 16615 connected: writing net test program
- X session ra pid 8045 slave 8046 disconnected: finishing up paper.3
- X csh%
- X
- Two other useful commands are ``sesswho'', to show all sessions on the
- system and their owners, and ``sesswhere'', to show where those sessions
- are currently connected to. (The system administrator may disable these
- commands for security reasons.)
- X
- X
- X4. Advanced session management techniques
- X
- By combining the sess, disconnect, and reconnect commands in simple
- ways, a user can perform surprisingly powerful session operations. In
- this section we give some such combinations. The reader may enjoy
- drawing pictures to see how the commands work.
- X
- A user can reconnect to a disconnected session without finishing the
- current session with ``sess reconnect xx''. Another method for doing an
- immediate reconnect is ``reconnect xx; disconnect''. The second method
- is symmetric: if the original session was yy, the user can flip back and
- forth with
- X
- X csh-yy% reconnect xx; disconnect
- X ...
- X ksh-xx% reconnect yy; disconnect
- X ...
- X csh-yy% reconnect xx; disconnect
- X
- and so on. To immediately reconnect to another session and finish the
- current session, he can use ``reconnect xx; exit'' or ``exec reconnect xx''.
- X
- Say a user is in the middle of something---running a crucial
- computation, perhaps, or ``talk''ing to another user---and decides to
- record what's happening. With sess, reconnect, and disconnect, he can do
- this without starting the program again:
- X
- X [talk session going on, user types ^Z]
- X Stopped
- X csh% sess sh
- X $ sessname; disconnect
- X session rf
- X csh% reconnect rf; disconnect
- X reconnect: will connect to session rf when session p8 is done
- X pty: info: reconnecting to rf
- X pty: info: successfully connected to rf
- X $ sess reconnect p8 | tee talk-record
- X reconnect: will connect to session p8 when session q0 is done
- X pty: info: reconnecting to p8
- X pty: info: successfully connected to p8
- X csh% fg
- X [talk session continues as before]
- X
- Now everything in session p8 is recorded in talk-record. The recording
- is completely transparent and does not require that ``talk'' be
- terminated or restarted.
- X
- X
- X5. Where to find it
- X
- The session management system described here is freely available as part
- of the pty 4.0 package. pty 4.0 works on BSD-derived UNIX systems.
- X
- The author's session management model is based on Bellovin's ``Session
- Tty'' Manager [1], which is not as powerful as pty but is better
- integrated into the login system.
- X
- X
- References
- X
- X[1] Bellovin, S. M. The ``Session Tty'' Manager. In USENIX Conference
- Proceedings, San Francisco, Summer 1988, 339-354.
- END_OF_FILE
- if test 11273 -ne `wc -c <'SESS.draft2'`; then
- echo shar: \"'SESS.draft2'\" unpacked with wrong size!
- fi
- # end of 'SESS.draft2'
- fi
- if test -f 'ptymain.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ptymain.c'\"
- else
- echo shar: Extracting \"'ptymain.c'\" \(16035 characters\)
- sed "s/^X//" >'ptymain.c' <<'END_OF_FILE'
- X#include <signal.h>
- X#include "sigsched.h"
- X#include "getoptquiet.h"
- X#include "ralloc.h"
- X#include "env.h"
- X#include "fmt.h"
- X#include "config/ptydir.h"
- X#include "config/ttyopts.h"
- X#include "config/ptyopts.h"
- X#include "config/posix.h"
- X#include "ptyget.h"
- X#include "ptytty.h"
- X#include "ptylogs.h"
- X#include "ptymisc.h"
- X#include "ptytexts.h"
- X#include "ptycomm.h"
- X#include "ptymaster.h"
- X#include "ptysigler.h"
- X#include "ptyerr.h"
- X#include "ptyslave.h"
- X#include "sesslog.h"
- X#include "sessconnlog.h"
- X
- X#define verbose 0, /*XXX*/
- X
- X/* XXX Exported to other files: */
- int flagxutmp = 0;
- int flagxwtmp = 0;
- X
- X/* Private flags: */
- static int flagxchown = 0;
- static int flagxexcl = 0; /* should be 1, but that'd break write & friends */
- static int flagxerrwo = 0; /* should be 1, but that'd break csh & more */
- static int flagxrandom = 1;
- static int flagxflowctl = 0; /* shouldn't have to exist */
- static int flagxonlysecure = 0; /* XXX: which one is right? */
- X
- static int flagreading = 1;
- static int flagdetached = 0;
- static int flagverbose = 1;
- static int flagjobctrl = 1;
- static int flagttymodes = 1;
- static int flagsameerr = 0;
- static int flagsession = 0;
- X
- static int flagpcbreak = 0; /* -pc, character-at-a-time */
- static int flagpnew = 1; /* -pd, new line discipline---traditionally off to start */
- static int flagpecho = 1; /* -pe, echo characters */
- static int flagpcrmod = 1; /* -pn, munge carriage returns */
- static int flagpraw = 0; /* -pr, raw mode */
- static int flagpcrt = 1; /* -ps, screen */
- static int flagp8bit = 1; /* -p8, 8-bit data path---traditionally off */
- X
- static int uid = -1; /* no harm in being safe */
- static char *username;
- static char *host;
- static char *remote;
- static char **program;
- X
- void setupsessionfiles(fdmty,fdsty,ext) /* XXX: move into master? */
- int fdmty;
- int fdsty;
- char *ext;
- X{
- X struct sesslog sl;
- X long t;
- X t = now();
- X if (utmp_on(ext,username,host,t) == -1)
- X {
- X warn("warning","cannot write utmp entry");
- X }
- X if (wtmp_on(ext,username,host,t) == -1)
- X {
- X warn("warning","cannot write wtmp entry");
- X utmp_off(ext,host,t); /* if this fails, too bad */
- X }
- X sesslog_fill(&sl,ext,username,uid,getpid(),t);
- X if (sesslog(&sl) == -1)
- X {
- X warn("warning","cannot write sesslog entry");
- X utmp_off(ext,host,t);
- X wtmp_off(ext,host,t);
- X }
- X /* sessconn will be handled later---remember, we start out disconnected! */
- X}
- X
- static int eachpty(ext)
- char *ext;
- X{
- X int fdtty;
- X
- X verbose("trying %c%c",ext[0],ext[1]);
- X
- X /* Note that there are several situations in which dissociation will fail. */
- X /* Fortunately, pty doesn't really care. */
- X fdtty = tty_getctrl();
- X /* note that we do this whether or not flagdetached */
- X if (tty_dissoc(fdtty) == -1)
- X warn("warning","cannot dissociate from current tty");
- X if (fdtty != -1)
- X close(fdtty);
- X return 0;
- X}
- X
- X/* for sigler if flagttymodes: */
- static struct ttymodes tmotty; /* original tty modes */
- static struct ttymodes tmottyzero; /* zero tty modes */
- X
- void startup(n)
- int n;
- X{
- X int pims[2];
- X int pimc[2];
- X int pid;
- X int fdmty;
- X int fdsty;
- X char ext[2];
- X int r1;
- X int r2;
- X char ch;
- X int fdcomm;
- X struct ttymodes ptymodes;
- X
- X r1 = 0;
- X r2 = 0;
- X if (flagxrandom)
- X {
- X r1 = getpid();
- X r2 = 37 * getpid() + (int) now;
- X }
- X
- X if (pipe(pims) == -1)
- X {
- X warn("fatal","cannot create internal pipe");
- X die(DIE_IMPOSSIBLE);
- X }
- X if (pipe(pimc) == -1)
- X {
- X warn("fatal","cannot create internal pipe");
- X die(DIE_IMPOSSIBLE);
- X }
- X
- X if (!flagdetached)
- X {
- X int fdtty;
- X
- X if ((fdtty = tty_getctrl()) == -1)
- X {
- X warn("fatal","cannot find controlling tty; try -d?");
- X die(DIE_NOCTTY);
- X }
- X
- X if (flagreading)
- X if (tty_forcefg(fdtty) == -1)
- X {
- X warn("fatal","cannot force myself into foreground; try -R?");
- X die(DIE_SETMODES);
- X }
- X /* The concept of !flagreading has a major problem: It's unsafe. We may */
- X /* end up with someone else's tty modes. */
- X if (tty_getmodes(fdtty,&ptymodes) == -1)
- X {
- X warn("fatal","cannot get modes of original tty");
- X die(DIE_GETMODES);
- X }
- X
- X close(fdtty);
- X }
- X else
- X {
- X tty_initmodes(&ptymodes);
- X flagpcbreak |= 2; flagpnew |= 2; flagpecho |= 2;
- X flagpcrmod |= 2; flagpraw |= 2; flagpcrt |= 2;
- X flagp8bit |= 2;
- X }
- X
- X tty_mungemodes(&ptymodes,
- X flagpcbreak,flagpnew,flagpecho,flagpcrmod,flagpraw,flagpcrt,flagp8bit);
- X
- X switch(pid = fork())
- X {
- X case -1:
- X warn("fatal","cannot fork master");
- X die(DIE_FORK);
- X case 0: /* master-slave */
- X#ifdef POSIX_SILLINESS
- X if (setsid() == -1) /* cannot fail---we're not a pgrp leader after fork */
- X {
- X warn("fatal","cannot setsid");
- X die(DIE_IMPOSSIBLE);
- X }
- X#endif
- X if (flagxonlysecure == -1)
- X {
- X if (getfreepty(&fdmty,&fdsty,ext,r1,r2,eachpty,flagxchown,1) == -1)
- X {
- X warn("fatal","no ptys available");
- X ch = DIE_NOPTYS; write(pims[1],&ch,1); /* XXX */
- X die(DIE_NOPTYS);
- X }
- X }
- X else if (getfreepty(&fdmty,&fdsty,ext,r1,r2,eachpty,flagxchown,0) == -1)
- X {
- X warn("warning","no secure ptys available");
- X if ((flagxonlysecure == 1) ||
- X (getfreepty(&fdmty,&fdsty,ext,r1,r2,eachpty,flagxchown,1) == -1))
- X {
- X warn("fatal","no ptys available");
- X ch = DIE_NOPTYS; write(pims[1],&ch,1); /* XXX */
- X die(DIE_NOPTYS);
- X }
- X }
- X if (flagverbose > 1)
- X {
- X char buf[50]; char *t; t = buf;
- X t += fmt_strncpy(t,"using pty ",0);
- X *t++ = ext[0]; *t++ = ext[1]; *t = 0;
- X warn("info",buf);
- X }
- X switch(pid = fork())
- X {
- X case -1:
- X warn("fatal","cannot fork slave");
- X ch = DIE_FORK; write(pims[1],&ch,1); /* XXX */
- X die(DIE_FORK);
- X case 0: /* slave */
- X signal(SIGTTOU,SIG_DFL); /* XXX: restore to original? */
- X signal(SIGTTIN,SIG_DFL);
- X signal(SIGPIPE,SIG_DFL);
- X close(pims[0]);
- X close(pims[1]);
- X close(pimc[1]);
- X close(fdmty);
- X verbose("slave waiting...");
- X if ((read(pimc[0],&ch,1) < 1) || (ch != 'k'))
- X {
- X warn("fatal","slave unable to read success code from master");
- X die(1);
- X }
- X close(pimc[0]);
- X verbose("slave starting...");
- X slave(fdsty,ext,program,flagxerrwo,flagsameerr,uid,flagverbose,flagxexcl);
- X return;
- X default: /* master */
- X if (setreuid(geteuid(),geteuid()) == -1)
- X {
- X warn("fatal","master unable to set its uids");
- X ch = DIE_IMPOSSIBLE; write(pims[1],&ch,1); /* XXX */
- X die(DIE_IMPOSSIBLE);
- X }
- X signal(SIGHUP,SIG_IGN);
- X signal(SIGTSTP,SIG_IGN);
- X signal(SIGINT,SIG_IGN);
- X signal(SIGQUIT,SIG_IGN);
- X#ifdef TTY_WINDOWS
- X signal(SIGWINCH,SIG_IGN);
- X#endif
- X /* We are now completely isolated from tty and I/O signals. */
- X verbose("master setting modes...");
- X if (tty_setmodes(fdsty,&ptymodes) == -1)
- X {
- X warn("fatal","master unable to set modes of pseudo-tty");
- X ch = DIE_SETMODES; write(pims[1],&ch,1); /* XXX */
- X die(DIE_SETMODES);
- X }
- X if (chdir(PTYDIR) == -1)
- X {
- X warn("fatal","master cannot chdir to pty directory; is it set up correctly?");
- X ch = DIE_PTYDIR; write(pims[1],&ch,1); /* XXX */
- X die(DIE_PTYDIR);
- X }
- X if ((fdcomm = comm_read(ext,uid)) == -1)
- X {
- X warn("fatal","master cannot create socket; is pty dir set up correctly?");
- X ch = DIE_ELSE; write(pims[1],&ch,1); /* XXX */
- X die(DIE_ELSE);
- X }
- X setupsessionfiles(fdmty,fdsty,ext);
- X if (write(pims[1],ext,2) != 2)
- X ; /* wtf? can't break pipe---we haven't closed it! */
- X close(pims[0]);
- X close(pims[1]);
- X close(pimc[0]);
- X close(0);
- X close(1);
- X close(2); /* XXX: this leaves master without a good error fd */
- X verbose("master starting...");
- X master(fdcomm,fdmty,fdsty,ext,uid,pid,flagsession,pimc[1],username,flagxflowctl);
- X return;
- X }
- X break;
- X default: /* sigler */
- X signal(SIGTTOU,SIG_DFL);
- X signal(SIGTTIN,SIG_DFL);
- X signal(SIGPIPE,SIG_DFL);
- X if (chdir(PTYDIR) == -1)
- X {
- X warn("fatal","signaller cannot chdir to pty directory; is it set up?");
- X die(DIE_PTYDIR);
- X }
- X close(pims[1]);
- X close(pimc[0]);
- X close(pimc[1]);
- X switch(read(pims[0],ext,2))
- X {
- X case 1: /* XXX: master has already printed an error */
- X die((int) ext[0]); /* XXX */
- X case 2:
- X break;
- X default:
- X warn("fatal","signaller cannot read success code from master");
- X die(DIE_COMM);
- X break;
- X }
- X if (flagttymodes) /* which implies flagreading && !flagdetached */
- X {
- X int fdtty;
- X
- X if ((fdtty = tty_getctrl()) == -1)
- X {
- X warn("fatal","signaller cannot find controlling tty; try -T?");
- X die(DIE_NOCTTY);
- X }
- X if (tty_getmodes(fdtty,&tmotty) == -1)
- X {
- X warn("fatal","signaller cannot get modes of original tty; try -T?");
- X die(DIE_GETMODES);
- X }
- X tty_copymodes(&tmottyzero,&tmotty);
- X tty_zeromode(&tmottyzero);
- X if (tty_setmodes(fdtty,&tmottyzero) == -1)
- X {
- X tty_setmodes(fdtty,&tmotty); /* worth a try... */
- X warn("fatal","signaller cannot set modes of original tty; try -T?");
- X die(DIE_SETMODES);
- X }
- X close(fdtty);
- X }
- X close(pims[0]);
- X sigler(ext,uid,pid,flagttymodes,&tmotty,&tmottyzero,flagreading,flagjobctrl,remote);
- X }
- X}
- X
- static void outofmem(n)
- unsigned int n; /* number of bytes in failing malloc */
- X{
- X static char buf[] = "pty: fatal: out of memory\n";
- X /* XXX: if this is from master, we may die silently! */
- X bwrite(2,buf,sizeof(buf) - 1); /*XXXX*/
- X die(DIE_NOMEM);
- X}
- X
- static void usageerr(why,opt)
- int why;
- int opt;
- X{
- X static char buf[100];
- X char *t; t = buf;
- X switch(why)
- X {
- X case 'a':
- X warn("fatal","what program do you want to run?");
- X break;
- X case 'p':
- X t += fmt_strncpy(t,"unrecognized terminal mode option -p",0);
- X *t++ = opt; *t = 0;
- X warn("fatal",buf);
- X break;
- X case 'x':
- X t += fmt_strncpy(t,"unrecognized security option -x",0);
- X *t++ = opt; *t = 0;
- X warn("fatal",buf);
- X break;
- X case 'u':
- X t += fmt_strncpy(t,"unrecognized option -",0);
- X *t++ = optproblem; *t = 0;
- X warn("fatal",buf);
- X break;
- X case 'o':
- X t += fmt_strncpy(t,"option -",0);
- X *t++ = optproblem;
- X t += fmt_strncpy(t," requires an argument",0);
- X *t = 0;
- X warn("fatal",buf);
- X break;
- X }
- X info(ptyusage);
- X die(DIE_USAGE);
- X}
- X
- main(argc,argv,envp)
- int argc;
- char *argv[];
- char *envp[];
- X{
- X int opt;
- X char *s;
- X int i;
- X char *proto;
- X char *protoremote;
- X
- X/* Stage 1: Initial security checks. */
- X if (forceopen(0) || forceopen(1) || forceopen(2) || forceopen(3))
- X {
- X warn("fatal","cannot set up open descriptors");
- X die(DIE_SETUP);
- X }
- X
- X/* Stage 2: Figure out userid and username. */
- X uid = getuid();
- X /* Preserve LOGNAME or USER if it's accurate. */
- X s = env_get("LOGNAME");
- X if (!s)
- X s = env_get("USER");
- X if (s && (username2uid(s,&i) != -1) && (i == uid))
- X username = s;
- X else
- X uid2username(uid,&username);
- X
- X/* Stage 3: Guess at host and remote for system logs. */
- X host = 0;
- X remote = 0;
- X
- X proto = env_get("PROTO");
- X if (proto)
- X {
- X protoremote = ralloc(strlen(proto) + 10);
- X if (protoremote)
- X {
- X s = protoremote;
- X s += fmt_strncpy(s,proto,0);
- X fmt_strncpy(s,"REMOTE",0);
- X s = env_get(protoremote);
- X rfree(protoremote);
- X if (s)
- X {
- X remote = ralloc(strlen(proto) + strlen(s) + 10);
- X if (remote)
- X {
- X char *t;
- X t = remote;
- X t += fmt_strncpy(t,proto,0);
- X t += fmt_strncpy(t,":",0);
- X fmt_strncpy(t,s,0);
- X if (proto[0] == 'T' && proto[1] == 'C' && proto[2] == 'P' && !proto[3])
- X { /* might as well assign host as well */
- X t = remote;
- X while (*t != '@') ++t; ++t;
- X while (*t != '(') ++t; ++t;
- X host = ralloc(strlen(t) + 4);
- X if (host)
- X {
- X fmt_strncpy(host,t,0);
- X t = host;
- X while (*t != ')') ++t;
- X *t = 0;
- X }
- X }
- X }
- X else
- X remote = 0;
- X }
- X }
- X }
- X if (!host)
- X host = "pty4.0";
- X if (!remote)
- X remote = "(unknown)";
- X
- X/* Stage 4: Process options. */
- X while ((opt = getopt(argc,argv,"ACHUVWqQvdDe3EjJsStTp:x:0rRh:O:")) != opteof)
- X switch(opt)
- X {
- X case 'A': info(ptyauthor); die(DIE_USAGE); break;
- X case 'C': info(ptycopyright); die(DIE_USAGE); break;
- X case 'H': info(ptyhelp); die(DIE_USAGE); break;
- X case 'U': info(ptyusage); die(DIE_USAGE); break;
- X case 'V': info(ptyversion); die(DIE_USAGE); break;
- X case 'W': info(ptywarranty); die(DIE_USAGE); break;
- X case 'h': host = optarg; break;
- X case 'O': remote = optarg; break;
- X case 'q': flagverbose = 0; break;
- X case 'Q': flagverbose = 1; break;
- X case 'v': flagverbose = 2; break;
- X case 'd': flagdetached = 1; flagjobctrl = 0; flagttymodes = 0; break;
- X case 'D': flagdetached = 0; flagjobctrl = 1; flagttymodes = 1; break;
- X case 'e': flagsameerr = 2; break;
- X case '3': flagsameerr = 1; break;
- X case 'E': flagsameerr = 0; break;
- X case 'j': flagjobctrl = 1; break;
- X case 'J': flagjobctrl = 0; break;
- X case 'r': flagreading = 1; break;
- X case 'R': flagreading = 0; break;
- X case 's': flagsession = 1; flagxutmp = 1; break;
- X case 'S': flagsession = 0; flagxutmp = 0; break;
- X case 't': flagttymodes = 1; break;
- X case 'T': flagttymodes = 0; break;
- X case '0': flagsameerr = 2; flagsession = 0; flagttymodes = 0;
- X flagxutmp = 0; /* XXX: also flagxwtmp = 0? */
- X flagpcbreak = 3; flagpraw = 3; flagpecho = 2; flagpnew = 2;
- X flagpcrmod = 2;
- X /* XXXXXX: is this sensible behavior? */
- X break;
- X case 'p':
- X while (opt = *(optarg++))
- X switch(opt)
- X {
- X case 'c': flagpcbreak = 3; break;
- X case 'C': flagpcbreak = 2; break;
- X case 'd': flagpnew = 3; break;
- X case 'D': flagpnew = 2; break;
- X case 'e': flagpecho = 3; break;
- X case 'E': flagpecho = 2; break;
- X case '7': flagp8bit = 2; break;
- X case '8': flagp8bit = 3; break;
- X case 'n': flagpcrmod = 3; break;
- X case 'N': flagpcrmod = 2; break;
- X case 'r': flagpraw = 3; break;
- X case 'R': flagpraw = 2; break;
- X case 's': flagpcrt = 3; break;
- X case 'S': flagpcrt = 2; break;
- X case '0': flagpcbreak = 3; flagpraw = 3;
- X flagpecho = 2; flagpnew = 2;
- X flagpcrmod = 2;
- X break;
- X default: usageerr('p',opt); break;
- X }
- X break;
- X case 'x':
- X while (opt = *(optarg++))
- X switch(opt)
- X {
- X case 'c': flagxchown = 1; break;
- X case 'C': flagxchown = 0; break;
- X case 'f': flagxflowctl = 1; break;
- X case 'F': flagxflowctl = 0; break;
- X case 'u': flagxutmp = 1; break;
- X case 'U': flagxutmp = 0; break;
- X case 'w': flagxwtmp = 1; break;
- X case 'W': flagxwtmp = 0; break;
- X case 'x': flagxexcl = 1; break;
- X case 'X': flagxexcl = 0; break;
- X case 'e': flagxerrwo = 1; break;
- X case 'E': flagxerrwo = 0; break;
- X case 'r': flagxrandom = 1; break;
- X case 'R': flagxrandom = 0; break;
- X case 's': flagxonlysecure = 1; break;
- X case 'S': flagxonlysecure = 0; break;
- X case 'i': flagxonlysecure = -1; break;
- X default: usageerr('x',opt); break;
- X }
- X break;
- X case '?':
- X default:
- X usageerr(argv[optind] ? 'u' : 'o',opt); break;
- X }
- X argc -= optind;
- X argv += optind;
- X
- X program = argv;
- X if (!*program)
- X usageerr('a',opt);
- X
- X/* Stage 5: Munge options. */
- X
- X#ifdef MUSTNOT_SESSION
- X if (flagsession) { flagsession = 0; warn("info","-s forced off"); }
- X#endif
- X#ifdef MUSTNOT_UTMPHOST
- X host = "pty4.0";
- X#endif
- X#ifdef MUSTNOT_UTMP
- X if (flagxutmp) { flagxutmp = 0; warn("info","-xu forced off"); }
- X#endif
- X#ifdef MUSTNOT_WTMP
- X if (flagxwtmp) { flagxwtmp = 0; warn("info","-xw forced off"); }
- X#endif
- X#ifdef MUSTNOT_CHOWN
- X if (flagxchown) { flagxchown = 0; warn("info","-xc forced off"); }
- X#endif
- X
- X if (flagsession) flagsameerr = 0;
- X if (flagdetached) flagttymodes = 0;
- X if (!flagreading) flagttymodes = 0;
- X
- X if (!flagsession)
- X {
- X sesslog_disable();
- X sessconnlog_disable();
- X }
- X if (!flagverbose)
- X warn_disable();
- X
- X/* Stage 6: Set up signals and enter sigsched. */
- X rallocneverfail(outofmem);
- X
- X ss_addsig(SIGCHLD);
- X ss_addsig(SIGHUP);
- X ss_addsig(SIGTSTP);
- X ss_addsig(SIGINT);
- X ss_addsig(SIGQUIT);
- X#ifdef TTY_WINDOWS
- X ss_addsig(SIGWINCH);
- X#endif
- X signal(SIGTTOU,SIG_IGN);
- X signal(SIGTTIN,SIG_IGN);
- X signal(SIGPIPE,SIG_IGN);
- X
- X ss_schedonce(ss_asap(),startup,0);
- X ss_exec();
- X die(0);
- X}
- END_OF_FILE
- if test 16035 -ne `wc -c <'ptymain.c'`; then
- echo shar: \"'ptymain.c'\" unpacked with wrong size!
- fi
- # end of 'ptymain.c'
- fi
- if test -f 'sigsched.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sigsched.c'\"
- else
- echo shar: Extracting \"'sigsched.c'\" \(13289 characters\)
- sed "s/^X//" >'sigsched.c' <<'END_OF_FILE'
- X/* sigsched.c, sigsched.h: signal-schedule thread library
- Daniel J. Bernstein, brnstnd@nyu.edu.
- Depends on ralloc.h, sod.h, config/fdsettrouble.h.
- Requires BSDish environment: reliable signals, sig{vec,block,setmask}, select.
- X9/1/91: Added worst-case fdset, FD_ZERO, etc. definitions.
- X8/25/91: sigsched 1.1, public domain.
- X8/25/91: Fixed bug that sigs[sched->blah].r didn't force instant timeout.
- X8/25/91: Fixed bug that if select() returned -1 then fds were still checked.
- X7/21/91: Changed forever to a 1-hour wakeup.
- X7/19/91: Added isopen() to fix bug in case of bad descriptor.
- X7/18/91: Baseline. sigsched 1.0, public domain.
- No known patent problems.
- X
- Documentation in sigsched.3.
- X
- XXXX: how well do we clean up upon ss_exec() exit?
- X
- X*/
- X
- X#include <sys/types.h>
- X#include <sys/param.h>
- X#include <sys/time.h>
- X#include <signal.h>
- X#include <errno.h>
- X#include <fcntl.h>
- extern int errno;
- X#include "config/fdsettrouble.h"
- X#include "sigsched.h"
- X#include "ralloc.h"
- X#include "sod.h"
- X
- X/* XXX: should restore signal set exactly after ss_exec returns */
- X
- typedef int sigc_set; /*XXX */
- X
- X#define sigc_ismember(x,i) (*(x) & (1 << ((i) - 1)))
- X#define sigc_addset(x,i) (*(x) |= (1 << ((i) - 1)))
- X#define sigc_emptyset(x) (*(x) = 0)
- X
- X/* sigprocmask(SIG_UNBLOCK,xxxx,(sigc_set *) 0); */
- X#define sigc_unblock(x) (sigsetmask(sigblock(0) & ~*(x)))
- X/* sigprocmask(SIG_BLOCK,xxxx,(sigc_set *) 0); */
- X#define sigc_block(x) (sigblock(*(x)))
- X
- X#ifndef NSIG
- X#define NSIG 64 /* it's not as if any sane system has more than 32 */
- X#endif
- X
- X#define NUMSIGS NSIG
- X
- X#ifndef FD_SETSIZE
- X#define FD_SETSIZE 256
- X#endif
- X
- X#define NUMFDS FD_SETSIZE /* if select() can't handle it, we can't either */
- X
- X#ifdef LACKING_FD_ZERO
- X#define NFDBITS (sizeof(fd_mask) * NBBY)
- X#define FD_SET(n,p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
- X#define FD_ISSET(n,p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
- X#define FD_ZERO(p) bzero((caddr_t)(p),sizeof(*(p)))
- X#endif
- X
- X#ifdef DESPERATION_FD_SET
- X#undef NFDBITS
- X#undef FD_SET
- X#undef FD_ISSET
- X#undef FD_ZERO
- X#undef fd_set
- X#define fd_set long
- X#define FD_SET(n,p) ((*p) |= (1 << (n)))
- X#define FD_ISSET(n,p) ((*p) & (1 << (n)))
- X#define FD_ZERO(p) (*p = 0L)
- X#endif
- X
- X#define ASAP 1
- X#define SIGNAL 2
- X#define READ 3
- X#define WRITE 4
- X#define EXCEPT 5
- X#define JUNK 6
- X#define EXTERN 7
- X
- typedef struct { ss_sig s; int r; } ss_sigplus;
- X
- static ss_sigplus asap;
- static ss_sigplus sigs[NUMSIGS];
- static ss_sigplus reads[NUMFDS];
- static ss_sigplus writes[NUMFDS];
- static ss_sigplus excepts[NUMFDS];
- static ss_sigplus junk; /* special case for internal use */
- X
- static void initsigs()
- X{
- X int i;
- X asap.s.type = ASAP; asap.s.u.n = 0; asap.r = 0;
- X for (i = 0;i < NUMSIGS;++i)
- X { sigs[i].s.type = SIGNAL; sigs[i].s.u.n = i; sigs[i].r = 0; }
- X for (i = 0;i < NUMFDS;++i)
- X { reads[i].s.type = READ; reads[i].s.u.n = i; reads[i].r = 0; }
- X for (i = 0;i < NUMFDS;++i)
- X { writes[i].s.type = WRITE; writes[i].s.u.n = i; writes[i].r = 0; }
- X for (i = 0;i < NUMFDS;++i)
- X { excepts[i].s.type = EXCEPT; excepts[i].s.u.n = i; excepts[i].r = 0; }
- X junk.s.type = JUNK; junk.s.u.n = 0; junk.r = 0;
- X}
- X
- ss_sig *ss_asap()
- X{ return &(asap.s); }
- X#define OKsig(i) ((i >= 0) && (i < NUMSIGS))
- ss_sig *ss_signal(i) int i;
- X{ if (!OKsig(i)) return 0; return &(sigs[i].s); }
- X#define OKfd(fd) ((fd >= 0) && (fd < NUMFDS))
- ss_sig *ss_sigread(fd) int fd;
- X{ if (!OKfd(fd)) return 0; return &(reads[fd].s); }
- ss_sig *ss_sigwrite(fd) int fd;
- X{ if (!OKfd(fd)) return 0; return &(writes[fd].s); }
- ss_sig *ss_sigexcept(fd) int fd;
- X{ if (!OKfd(fd)) return 0; return &(excepts[fd].s); }
- X
- void ss_externsetsig(sig,x)
- ss_sig *sig;
- ss_extern *x;
- X{
- X sig->type = EXTERN;
- X sig->u.c = (char *) x;
- X}
- X
- struct sched
- X {
- X ss_sig *sig;
- X ss_thread *t;
- X union { ss_id i; ss_idptr p; } id;
- X int flagi;
- X int wait;
- X }
- X;
- X
- SODdecl(schedlist,struct sched);
- X
- static schedlist schedhead = 0;
- static int schednum = 0;
- static int schedjunked = 0;
- static int numwait = 0;
- X
- void ss_forcewait()
- X{
- X ++numwait;
- X}
- X
- void ss_unforcewait()
- X{
- X --numwait;
- X}
- X
- int ss_schedvwait(sig,t,flagi,i,p,wait)
- ss_sig *sig;
- ss_thread *t;
- int flagi;
- ss_id i;
- ss_idptr p;
- int wait;
- X{
- X schedlist s;
- X
- X if (sig->type == EXTERN)
- X {
- X ss_extern *x;
- X x = (ss_extern *) sig->u.c;
- X return x->sched(x,t,flagi,i,p,wait);
- X }
- X s = SODalloc(schedlist,s,ralloc);
- X if (!s)
- X return -1;
- X SODdata(s).sig = sig;
- X SODdata(s).t = t;
- X if (SODdata(s).flagi = flagi)
- X SODdata(s).id.i = i;
- X else
- X SODdata(s).id.p = p;
- X SODdata(s).wait = wait;
- X SODpush(schedhead,s);
- X ++schednum;
- X if (wait)
- X ++numwait;
- X return 0;
- X}
- X
- int ss_schedwait(sig,t,i,wait)
- ss_sig *sig;
- ss_thread *t;
- ss_id i;
- int wait;
- X{
- X return ss_schedvwait(sig,t,1,i,(ss_idptr) 0,wait);
- X}
- X
- int ss_sched(sig,t,i)
- ss_sig *sig;
- ss_thread *t;
- ss_id i;
- X{
- X return ss_schedvwait(sig,t,1,i,(ss_idptr) 0,0);
- X}
- X
- struct oncestuff { ss_sig *sig; ss_thread *t; ss_id i; } ;
- X/* XXX: this is the same as some other struct */
- X
- static void once(p)
- ss_idptr p;
- X{
- X struct oncestuff *os;
- X os = (struct oncestuff *) p;
- X if (ss_unschedv(os->sig,once,0,0,p) == -1)
- X ; /* impossible */
- X os->t(os->i);
- X RFREE(os);
- X}
- X
- int ss_schedonce(sig,t,i)
- ss_sig *sig;
- ss_thread *t;
- ss_id i;
- X{
- X struct oncestuff *os;
- X
- X os = (struct oncestuff *) ralloc(sizeof(struct oncestuff));
- X if (!os)
- X return -1;
- X os->sig = sig; os->t = t; os->i = i;
- X return ss_schedvwait(sig,once,0,0,(ss_idptr) os,1);
- X}
- X
- X/* XXX: could rallocinstall() this, if it has the recvhead() test */
- X
- static int schedcleanup()
- X{
- X schedlist s;
- X schedlist t;
- X schedlist sprev;
- X
- X/* if (recvhead) return 0; XXX: needs recvhead in scope */
- X
- X if (!schedjunked)
- X return 0;
- X
- X sprev = 0;
- X s = schedhead;
- X while (s)
- X {
- X if (SODdata(s).sig == &(junk.s))
- X {
- X if (sprev)
- X {
- X SODpop(SODnext(sprev),t); /* XXX: not part of official sod interface */
- X s = SODnext(sprev);
- X }
- X else
- X {
- X SODpop(s,t);
- X schedhead = s;
- X }
- X SODfree(t,rfree);
- X --schednum;
- X --schedjunked;
- X }
- X else
- X {
- X sprev = s;
- X s = SODnext(s);
- X }
- X }
- X
- X/* schednum -= schedjunked; now done dynamically inside loop */
- X/* schedjunked = 0; */
- X return 1;
- X}
- X
- static void nothing(id)
- ss_id id;
- X{
- X ;
- X}
- X
- int ss_unschedv(sig,t,flagi,i,p)
- ss_sig *sig;
- ss_thread *t;
- int flagi;
- ss_id i;
- ss_idptr p;
- X{
- X schedlist s;
- X
- X if (sig->type == EXTERN)
- X {
- X ss_extern *x;
- X x = (ss_extern *) sig->u.c;
- X return x->unsched(x,t,flagi,i,p);
- X }
- X for (s = schedhead;s;s = SODnext(s))
- X if (SODdata(s).sig == sig && SODdata(s).t == t)
- X if (SODdata(s).flagi == flagi)
- X if (flagi ? (SODdata(s).id.i == i) : (SODdata(s).id.p == p))
- X {
- X SODdata(s).sig = &(junk.s);
- X SODdata(s).t = nothing; /* just in case */
- X if (SODdata(s).wait)
- X --numwait;
- X SODdata(s).wait = 0;
- X ++schedjunked;
- X return 0;
- X }
- X return 1;
- X}
- X
- int ss_unsched(sig,t,i)
- ss_sig *sig;
- ss_thread *t;
- ss_id i;
- X{
- X return ss_unschedv(sig,t,1,i,(ss_idptr) 0);
- X}
- X
- static struct timeval timeout;
- static struct timeval instant = { 0, 0 };
- static struct timeval forever = { 3600, 0 };
- X /* XXX: talk to me */
- X
- static void handle(i)
- int i;
- X{
- X timeout = instant; /* XXX: structure copying */
- X sigs[i].r = 1;
- X}
- X
- static sigc_set sigstorage;
- static sigc_set *xxxx = 0;
- X
- int ss_addsig(i)
- int i;
- X{
- X if (!OKsig(i))
- X return -1;
- X if (!xxxx)
- X {
- X xxxx = &sigstorage;
- X sigc_emptyset(xxxx);
- X }
- X sigc_addset(xxxx,i);
- X return 0;
- X}
- X
- static int isopen(fd)
- int fd;
- X{
- X /* XXX: should call this only if select() fails */
- X return fcntl(fd,F_GETFL,0) != -1;
- X}
- X
- SODdecl(recvlist,schedlist);
- X
- int ss_exec()
- X{
- X int i;
- X struct sigvec sv;
- X recvlist recvhead;
- X recvlist temp;
- X schedlist sch;
- X
- X initsigs();
- X
- X if (xxxx)
- X {
- X sigc_block(xxxx);
- X
- X sv.sv_handler = handle;
- X sv.sv_mask = *xxxx; /* so handle won't interrupt itself */
- X sv.sv_flags = 0;
- X
- X /* XXX: Does anyone but me find it absolutely idiotic that POSIX
- X doesn't provide a way to get each member of a signal set in turn? */
- X for (i = 0;i < NUMSIGS;i++)
- X {
- X if (sigc_ismember(xxxx,i))
- X if (sigvec(i,&sv,(struct sigvec *) 0) == -1) /*XXX: really trash orig? */
- X ; /* not our problem */
- X }
- X }
- X
- X recvhead = 0;
- X
- X while (numwait)
- X {
- X if (recvhead)
- X {
- X int w;
- X SODpop(recvhead,temp);
- X sch = SODdata(temp);
- X
- X/* This is the only section where we call user code. */
- X#define DOIT \
- if (SODdata(sch).flagi) \
- X SODdata(sch).t(SODdata(sch).id.i); \
- else \
- X SODdata(sch).t(SODdata(sch).id.p);
- X
- X switch(SODdata(sch).sig->type)
- X {
- X case JUNK:
- X break; /* has been unscheduled while waiting on the receive list */
- X case ASAP:
- X DOIT
- X break;
- X case READ:
- X if (reads[w = SODdata(sch).sig->u.n].r)
- X DOIT
- X reads[w].r = 0;
- X break;
- X case WRITE:
- X if (writes[w = SODdata(sch).sig->u.n].r)
- X DOIT
- X writes[w].r = 0;
- X break;
- X case EXCEPT:
- X if (excepts[w = SODdata(sch).sig->u.n].r)
- X DOIT
- X excepts[w].r = 0;
- X break;
- X case SIGNAL:
- X if (sigs[w = SODdata(sch).sig->u.n].r)
- X DOIT
- X sigs[w].r = 0;
- X /* ``after the end of the last...'' */
- X break;
- X case EXTERN:
- X /* by definition, an external library handles this */
- X break;
- X default: /* XXX: huh? */
- X ;
- X }
- X SODfree(temp,rfree);
- X }
- X else
- X {
- X schedlist sp;
- X static fd_set rfds;
- X static fd_set wfds;
- X static fd_set efds;
- X static int maxfd;
- X int r;
- X
- X if (schedjunked > 100)
- X if (schednum / schedjunked < 3)
- X (void) schedcleanup(); /* now's as good a time as any */
- X
- X timeout = forever;
- X FD_ZERO(&rfds);
- X FD_ZERO(&wfds);
- X FD_ZERO(&efds);
- X maxfd = -1;
- X
- X for (sp = schedhead;sp;sp = SODnext(sp))
- X {
- X switch(SODdata(sp).sig->type)
- X {
- X case JUNK:
- X break;
- X case ASAP:
- X timeout = instant;
- X break;
- X case SIGNAL:
- X if (sigs[SODdata(sp).sig->u.n].r)
- X timeout = instant;
- X break;
- X case READ:
- X if (isopen(SODdata(sp).sig->u.n))
- X FD_SET(SODdata(sp).sig->u.n,&rfds);
- X if (SODdata(sp).sig->u.n > maxfd)
- X maxfd = SODdata(sp).sig->u.n;
- X break;
- X case WRITE:
- X if (isopen(SODdata(sp).sig->u.n))
- X FD_SET(SODdata(sp).sig->u.n,&wfds);
- X if (SODdata(sp).sig->u.n > maxfd)
- X maxfd = SODdata(sp).sig->u.n;
- X break;
- X case EXCEPT:
- X if (isopen(SODdata(sp).sig->u.n))
- X FD_SET(SODdata(sp).sig->u.n,&efds);
- X if (SODdata(sp).sig->u.n > maxfd)
- X maxfd = SODdata(sp).sig->u.n;
- X break;
- X case EXTERN:
- X break;
- X default: /*XXX: huh? */
- X break;
- X }
- X }
- X
- X if (xxxx)
- X sigc_unblock(xxxx);
- X /* This is the only section where handle() can be called. */
- X /* XXX: If maxfd == -1, this select functions as a pause. */
- X /* XXX: If maxfd == -1 and timeout is instant, should skip select. */
- X /* XXX: Random bug of note: Real BSD systems will say that the
- X fd is writable as soon as a network connect() fails. The first
- X I/O will show the error (though it's rather stupid that you
- X can't find out the error without doing I/O). What does Ultrix
- X 4.1 do? It pauses for 75 seconds. Dolts. */
- X r = select(maxfd + 1,&rfds,&wfds,&efds,&timeout);
- X /* XXX: does this necessarily prevent timeout race conditions? */
- X if (xxxx)
- X sigc_block(xxxx);
- X
- X if (r == -1)
- X {
- X FD_ZERO(&rfds);
- X FD_ZERO(&wfds);
- X FD_ZERO(&efds);
- X switch(errno)
- X {
- X case EINTR: /* fine, this will happen on any signal */ break;
- X case EBADF: /* who knows? */ break;
- X case EINVAL: /* simply impossible */ break;
- X default: /*XXX*/ ;
- X /* well, that was real useful */
- X }
- X }
- X
- X for (sp = schedhead;sp;sp = SODnext(sp))
- X {
- X switch(SODdata(sp).sig->type)
- X {
- X case JUNK:
- X break;
- X case ASAP:
- X temp = SODalloc(recvlist,temp,ralloc);
- X if (!temp)
- X return -1; /*XXX*/
- X SODdata(temp) = sp;
- X SODpush(recvhead,temp);
- X break;
- X case SIGNAL:
- X if (sigs[SODdata(sp).sig->u.n].r)
- X {
- X temp = SODalloc(recvlist,temp,ralloc);
- X if (!temp)
- X return -1; /*XXX*/
- X SODdata(temp) = sp;
- X SODpush(recvhead,temp);
- X }
- X break;
- X case READ:
- X if (FD_ISSET(SODdata(sp).sig->u.n,&rfds))
- X {
- X FD_CLR(SODdata(sp).sig->u.n,&rfds);
- X reads[SODdata(sp).sig->u.n].r = 1;
- X temp = SODalloc(recvlist,temp,ralloc);
- X if (!temp)
- X return -1; /*XXX*/
- X SODdata(temp) = sp;
- X SODpush(recvhead,temp);
- X }
- X break;
- X case WRITE:
- X if (FD_ISSET(SODdata(sp).sig->u.n,&wfds))
- X {
- X FD_CLR(SODdata(sp).sig->u.n,&wfds);
- X writes[SODdata(sp).sig->u.n].r = 1;
- X temp = SODalloc(recvlist,temp,ralloc);
- X if (!temp)
- X return -1; /*XXX*/
- X SODdata(temp) = sp;
- X SODpush(recvhead,temp);
- X }
- X break;
- X case EXCEPT:
- X if (FD_ISSET(SODdata(sp).sig->u.n,&efds))
- X {
- X FD_CLR(SODdata(sp).sig->u.n,&efds);
- X excepts[SODdata(sp).sig->u.n].r = 1;
- X temp = SODalloc(recvlist,temp,ralloc);
- X if (!temp)
- X return -1; /*XXX*/
- X SODdata(temp) = sp;
- X SODpush(recvhead,temp);
- X }
- X break;
- X case EXTERN:
- X break;
- X default:
- X break;
- X }
- X }
- X }
- X }
- X if (xxxx)
- X sigc_unblock(xxxx);
- X /* XXX: should put this at other returns as well */
- X return 0;
- X}
- END_OF_FILE
- if test 13289 -ne `wc -c <'sigsched.c'`; then
- echo shar: \"'sigsched.c'\" unpacked with wrong size!
- fi
- # end of 'sigsched.c'
- fi
- echo shar: End of archive 7 \(of 9\).
- cp /dev/null ark7isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 9 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-